/*
 * Dumper.java   2008/07/28
 *
 * Copyright 2008 Web & Zen Multimedia, All rights reserved.
 * Use is subject to license terms.
 */
package it.wzm.lightweightlog;

import java.util.Properties;
import it.wzm.lightweightlog.annotation.OpeningProcessor;
import it.wzm.lightweightlog.annotation.DumpingProcessor;

/**
 * <p>
 * This abstract class and its methods represent the Dumper, which is the wrapper
 *    of the stream used to unload the Entry.<br>
 *    The Dumper is created at Log startup and is builded with a custom set of properties
 *    prepared and loaded by the LogFactory class. Every Dumper is then stored into a proper implementation
 * of {@link Register}. </p>
 * <p>
 *  When extending Dumper for creating a custom one, the Dumper will have a global
 *  set of variable taken either by the property file or if not found from the {@link
 *  Constant} interface. Other custom set of properties will have this basic rule.
 *  Giving the dumper.properties with this declaration:</p>
 * <p>dumper.name=<i>mydumper</i>,<i>otherdumper</i></p>
 * <p>Then the following properties has to have root:</p>
 * <p>
 * <blockquote>
 *  dumper.<i>mydumper</i>.property1=value<br>
 *  dumper.<i>mydumper</i>.property1=value<br>
 *  dumper.<i>otherdumper</i>.property3=value
 * </blockquote>
 * </p>
 * <p>
 *  In this way property1, property2 will be read only by <i>mydumper</i> and property3 only by
 *  <i>otherdumper</i>. The two dumpers cannot share each other their set of properties.
 * </p>
 * <p>
 *  For retrieving a custom property the method get(String name)
 *  serve the purpose. Supposing we want to get property <i>severity</i> for <i>mydumper</i>.
 * </p>
 * <p>
 *  <i>dumper.mydumper.severity=INFO</i><br/>
 *  is retrieved by calling:<br>
 *  <i>this.get("severity");</i><br/>
 *  The method will then reconstruct internally kind of:<br/>
 *  <i>property.getProperty(PROP_ROOT + name + key);</i><br/>
 *  and return <i>INFO</i><br/>
 * </p>
 * <p>
 *  Following is a list of global Dumper variables and their explanation, see the
 *  {@link Constant} interface for their default value.</p>
 * <ul>
 *    <li><i>killonfailure</i> = if a DumperException is thrown during operation and
 *        this value is true, then the Dumper.Status is set to FAILURE and the Dumper
 *        is declared invalid and removed by the Register.
 *    </li>
 *    <li><i>keepalive</i> = if true the dumper is always open, while this can have a meaning with
 *    file and database dumping, there are others on which this property has no effect such as the System.out dumper.</li>
 * </ul>
 * <p>
 * By default the Dumper is decorated, using the decorator pattern, with annotations which take care
 * of doing pre operation regarding the opening and closing of dumper, and the dumping process itself.
 * The decoration are inherited by extending dumper, but can be overridden using annotation in that classes.
 * </p>
 * @author Leonardo Celati
 * @version 1.0
 */
@DumpingProcessor(active=true, filtering=true)
@OpeningProcessor(active=true, keepingalive=true, killing=true)
public abstract class Dumper extends LightweightlogObject {
    
    /**
     * As required by serialization
     */
    private static final long serialVersionUID = 178957906062361835L;    

    /** What happen on error... */
    private boolean killOnFailure;
    /** Severity for this Dumper */
    private Severity severity;
    /** Tell if we want to keep this Dumper always open */
    private boolean keepAlive;
    
    /**
     * Default constructor
     */
    protected Dumper() {
    }
    
    /**
     * Build a Dumper passing a set of properties
     * @param p a custom set of properties
     */
    protected Dumper(String name, Properties p) {
        // super constructor...
    	super(name,p);
    	
        try {
            // performing the init...
            this.setStatus(Status.INIT);

            this.preinit();
            
            // severity for this Dumper, cannot have a default value
            // that's why we throw error if we cannot parse the property
            this.severity=Severity.valueOf( ((String)get("severity")).toUpperCase() );
            
            // kill ?
            try {
                this.killOnFailure = Boolean.parseBoolean( get("killonfailure").toLowerCase() );
            } catch (IllegalArgumentException e) {
                this.killOnFailure = DEFAULT_KILL_ON_FAILURE;
            }
            
            // keep alive ?
            try {
                this.keepAlive=Boolean.parseBoolean(get("keepalive").toLowerCase());
            } catch (Exception e) {
                this.keepAlive = DEFAULT_KEEP_ALIVE;
            }
            
            this.setStatus(Status.RUNNING);
            
        } catch (RuntimeException e) {
            this.setStatus(Status.FAILURE);
            throw new LightweightlogInitializationException(e.getMessage());
        } catch (Exception e) {
            this.setStatus(Status.FAILURE);
            throw new LightweightlogInitializationException(e.getMessage());
        }
    }
    
    /**
     * Pre initialization operation goes here
     */
    public void preinit() {    	
    }
    
    /**
     * Post initialization operation goes here
     */
    protected void postinit() {    	
    }
    
 
    /**
     * Getter for kill on failure
     * @return Severity
     */
    public boolean hasKillOnFailure() {
        return killOnFailure;
    }
    
    /**
     * We want this dumper always open
     * @return Severity
     */
    public boolean isKeepAlive() {
        return this.keepAlive;
    }
    
    /**
     * Getter for severity
     * @return Severity
     */
    public Severity getSeverity() {
        return this.severity;
    }
    
    /**
     * True or false if this Dumper is open
     * @return true/false
     */
    public abstract boolean isOpen();
    
    /**
     * Open this dumper for writing
     * @throws DumperException
     * @throws it.wzm.lightweightlog.DumperException if something went wrong
     */
    public abstract void open() throws DumperException;
    
    /**
     * Unload the Entry to the stream.
     * @param e A passed object extending {@link Entry}
     * @throws DumperException if something went wrong
     */
    public abstract <E extends Entry> void dump(E e) throws DumperException;
    
    /**
     * Extending classes are asked to implements this method,
     * any close or finalize action will goes here.
     * which close the logger
     * @throws DumperException
     */
    public abstract void close() throws DumperException;    
    
}
